/*
    Modified from The Boost Library
    Modified by : 2013 darkcat

    Copyright Kevlin Henney, 2000, 2001, 2002. All rights reserved.

    Distributed under the Boost Software License, Version 1.0. (See
    accompanying file LICENSE_1_0.txt or copy at
    http://www.boost.org/LICENSE_1_0.txt)
*/

#pragma once

// nx...
#include "config/general.h"
// nx::pointer
#include "memory/pointer.h"
// nx_assert
#include "bugfix/assert.h"
// nx::swap
#include "algorithm/algorithm.h"

// typeid
#include <typeinfo>

//////////////////////////////////////////////////////////////////////////
NX_BEG
//////////////////////////////////////////////////////////////////////////

class any
{
protected:
    class PlaceHolder
    {
    public:
        virtual ~PlaceHolder() {}

    public:
        virtual const std::type_info& type() const = 0;
        virtual PlaceHolder* clone() const = 0;
    };

    template <typename T>
    class Holder : public PlaceHolder
    {
    public:
        T held;

    public:
        Holder(const T& v): held(v) {}

    public:
        const std::type_info & type() const { return typeid(T); }
        PlaceHolder* clone() const { return nx::alloc<Holder>(held); }
    };

protected:
    ptr<PlaceHolder> content_;

public:
    any() {}

    template <typename T>
    any(const T& v)
        : content_(nx::alloc<Holder<T> >(v))
    {}

    any(const any& other)
        : content_(other.content_.get() ? other.content_->clone() : NX_NULL)
    {}

public:
    any& swap(any& rhs)
    {
        nx::swap(content_, rhs.content_);
        return *this;
    }

    template <typename T>
    any& operator=(const T& rhs)
    {
        any(rhs).swap(*this);
        return *this;
    }

    any& operator=(any rhs)
    {
        any(rhs).swap(*this);
        return *this;
    }

public:
    const std::type_info & type() const
    {
        return (content_.get() ? content_->type() : typeid(void));
    }
    
    bool empty() const
    {
        return (!content_.get());
    }
    
    void clear()
    {
        any().swap(*this);
    }

private:
    template <typename T>
    friend T any_cast(any&);
    template <typename T>
    friend T any_cast(const any&);
};

/*
    Special swap algorithm
*/

void swap(any& x, any& y)
{
    x.swap(y);
}

/*
    cast any to a exact type
*/

template <typename T>
T any_cast(any& operand)
{
    nx_assert(operand.type() == typeid(T));
    return pointer_cast<any::Holder<T> >(operand.content_)->held;
}

template <typename T>
T any_cast(const any& operand)
{
    return any_cast<T>(const_cast<any&>(operand));
}

//////////////////////////////////////////////////////////////////////////
NX_END
//////////////////////////////////////////////////////////////////////////
